1 // ----------------------------------------------------------------------------
2 // <copyright file=
"LoadbalancingPeer.cs" company="Exit Games GmbH">
3 // Loadbalancing Framework
for Photon - Copyright (C) 2011 Exit Games GmbH
4 // </copyright>
5 // <summary>
6 // Provides the operations needed to use the loadbalancing server app(s).
7 // </summary>
8 // <author>developer@exitgames.com</author>
9 // ----------------------------------------------------------------------------

10
11 using
ExitGames.Client.Photon;
12 using
ExitGames.Client.Photon.Lite;
13 using
System;
14 using
System.Collections.Generic;
15 using
Hashtable = ExitGames.Client.Photon.Hashtable;
16
17
18 namespace
ExitGames.Client.Photon
19 {

20     ///
<summary>
21     ///
Internally used by PUN, a LoadbalancingPeer provides the operations and enum
22     ///
definitions needed to use the Photon Loadbalancing server (or the Photon Cloud).
23     ///
</summary>
24     ///
<remarks>
25     ///
The LoadBalancingPeer does not keep a state, instead this is done by a LoadBalancingClient.
26     ///
</remarks>
27     
internal class LoadbalancingPeer : PhotonPeer
28     {
29         
private readonly Dictionary<byte, object> opParameters = new Dictionary<byte, object>(); // used in OpRaiseEvent() (avoids lots of new Dictionary() calls)
30
31         
public LoadbalancingPeer(IPhotonPeerListener listener, ConnectionProtocol protocolType) : base(listener, protocolType)
32         {
33         }
34
35         
public virtual bool OpGetRegions(string appId)
36         {
37             Dictionary<
byte, object> parameters = new Dictionary<byte, object>();
38             parameters[(
byte)ParameterCode.ApplicationId] = appId;
39
40             
return this.OpCustom(OperationCode.GetRegions, parameters, true, 0, true);
41         }

42
43         ///
<summary>
44         ///
Joins the lobby on the Master Server, where you get a list of RoomInfos of currently open rooms.
45         ///
This is an async request which triggers a OnOperationResponse() call.
46         ///
</summary>
47         ///
<returns>If the operation could be sent (has to be connected).</returns>
48         
public virtual bool OpJoinLobby(TypedLobby lobby)
49         {
50             
if (this.DebugOut >= DebugLevel.INFO)
51             {
52                 
this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinLobby()");
53             }
54
55             Dictionary<
byte, object> parameters = null;
56             
if (lobby != null && !lobby.IsDefault)
57             {
58                 parameters =
new Dictionary<byte, object>();
59                 parameters[(
byte)ParameterCode.LobbyName] = lobby.Name;
60                 parameters[(
byte)ParameterCode.LobbyType] = (byte)lobby.Type;
61             }
62
63             
return this.OpCustom(OperationCode.JoinLobby, parameters, true);
64         }

65
66         ///
<summary>
67         ///
Leaves the lobby on the Master Server.
68         ///
This is an async request which triggers a OnOperationResponse() call.
69         ///
</summary>
70         ///
<returns>If the operation could be sent (has to be connected).</returns>
71         
public virtual bool OpLeaveLobby()
72         {
73             
if (this.DebugOut >= DebugLevel.INFO)
74             {
75                 
this.Listener.DebugReturn(DebugLevel.INFO, "OpLeaveLobby()");
76             }
77
78             
return this.OpCustom(OperationCode.LeaveLobby, null, true);
79         }

80
81
82         ///
<summary>
83         ///
Don't use this method directly, unless you know how to cache and apply customActorProperties.
84         ///
The PhotonNetwork methods will handle player and room properties for you and call this method.
85         ///
</summary>
86         
public virtual bool OpCreateRoom(string roomName, RoomOptions roomOptions, TypedLobby lobby, Hashtable playerProperties, bool onGameServer)
87         {
88             
if (this.DebugOut >= DebugLevel.INFO)
89             {
90                 
this.Listener.DebugReturn(DebugLevel.INFO, "OpCreateRoom()");
91             }
92
93             Dictionary<
byte, object> op = new Dictionary<byte, object>();
94
95             
if (!string.IsNullOrEmpty(roomName))
96             {
97                 op[ParameterCode.RoomName] = roomName;
98             }
99             
if (lobby != null)
100             {
101                 op[ParameterCode.LobbyName] = lobby.Name;
102                 op[ParameterCode.LobbyType] = (
byte)lobby.Type;
103             }
104
105             
if (onGameServer)
106             {
107                 
if (playerProperties != null && playerProperties.Count > 0)
108                 {
109                     op[ParameterCode.PlayerProperties] = playerProperties;
110                     op[ParameterCode.Broadcast] =
true; // TODO: check if this also makes sense when creating a room?! // broadcast actor properties
111                 }
112
113
114                 
if (roomOptions == null)
115                 {
116                     roomOptions =
new RoomOptions();
117                 }
118
119                 Hashtable gameProperties =
new Hashtable();
120                 op[ParameterCode.GameProperties] = gameProperties;
121                 gameProperties.MergeStringKeys(roomOptions.customRoomProperties);
122
123                 gameProperties[GameProperties.IsOpen] = roomOptions.isOpen;
// TODO: check default value. dont send this then
124                 gameProperties[GameProperties.IsVisible] = roomOptions.isVisible;
// TODO: check default value. dont send this then
125                 gameProperties[GameProperties.PropsListedInLobby] = roomOptions.customRoomPropertiesForLobby;
126                 
if (roomOptions.maxPlayers > 0)
127                 {
128                     gameProperties[GameProperties.MaxPlayers] = roomOptions.maxPlayers;
129                 }
130                 
if (roomOptions.cleanupCacheOnLeave)
131                 {
132                     op[ParameterCode.CleanupCacheOnLeave] =
true; // this is actually setting the room's config
133                     gameProperties[GameProperties.CleanupCacheOnLeave] =
true; // this is only informational for the clients which join
134                 }
135             }
136
137             
// UnityEngine.Debug.Log("CreateGame: " + SupportClass.DictionaryToString(op));
138             
return this.OpCustom(OperationCode.CreateGame, op, true);
139         }

140
141
142         ///
<summary>LoadBalancingPeer.OpJoinRoom</summary>
143         
public virtual bool OpJoinRoom(string roomName, RoomOptions roomOptions, TypedLobby lobby, bool createIfNotExists, Hashtable playerProperties, bool onGameServer)
144         {
145             Dictionary<
byte, object> op = new Dictionary<byte, object>();
146
147             
if (!string.IsNullOrEmpty(roomName))
148             {
149                 op[ParameterCode.RoomName] = roomName;
150             }
151             
if (createIfNotExists)
152             {
153                 op[ParameterCode.CreateIfNotExists] =
true;
154                 
if (lobby != null)
155                 {
156                     op[ParameterCode.LobbyName] = lobby.Name;
157                     op[ParameterCode.LobbyType] = (
byte)lobby.Type;
158                 }
159             }
160
161             
if (onGameServer)
162             {
163                 
if (playerProperties != null && playerProperties.Count > 0)
164                 {
165                     op[ParameterCode.PlayerProperties] = playerProperties;
166                     op[ParameterCode.Broadcast] =
true; // broadcast actor properties
167                 }
168
169
170                 
if (createIfNotExists)
171                 {
172                     
if (roomOptions == null)
173                     {
174                         roomOptions =
new RoomOptions();
175                     }
176
177                     Hashtable gameProperties =
new Hashtable();
178                     op[ParameterCode.GameProperties] = gameProperties;
179                     gameProperties.MergeStringKeys(roomOptions.customRoomProperties);
180
181                     gameProperties[GameProperties.IsOpen] = roomOptions.isOpen;
182                     gameProperties[GameProperties.IsVisible] = roomOptions.isVisible;
183                     gameProperties[GameProperties.PropsListedInLobby] = roomOptions.customRoomPropertiesForLobby;
184                     
if (roomOptions.maxPlayers > 0)
185                     {
186                         gameProperties[GameProperties.MaxPlayers] = roomOptions.maxPlayers;
187                     }
188                     
if (roomOptions.cleanupCacheOnLeave)
189                     {
190                         op[ParameterCode.CleanupCacheOnLeave] =
true; // this is actually setting the room's config
191                         gameProperties[GameProperties.CleanupCacheOnLeave] =
true; // this is only informational for the clients which join
192                     }
193                 }
194             }
195
196             
// UnityEngine.Debug.Log("JoinGame: " + SupportClass.DictionaryToString(op));
197             
return this.OpCustom(OperationCode.JoinGame, op, true);
198         }

199
200
201         ///
<summary>
202         ///
Operation to join a random, available room. Overloads take additional player properties.
203         ///
This is an async request which triggers a OnOperationResponse() call.
204         ///
If all rooms are closed or full, the OperationResponse will have a returnCode of ErrorCode.NoRandomMatchFound.
205         ///
If successful, the OperationResponse contains a gameserver address and the name of some room.
206         ///
</summary>
207         ///
<param name="expectedCustomRoomProperties">Optional. A room will only be joined, if it matches these custom properties (with string keys).</param>
208         ///
<param name="expectedMaxPlayers">Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.</param>
209         ///
<param name="playerProperties">This player's properties (custom and well known).</param>
210         ///
<param name="matchingType">Selects one of the available matchmaking algorithms. See MatchmakingMode enum for options.</param>
211         ///
<returns>If the operation could be sent currently (requires connection).</returns>
212         
public virtual bool OpJoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers, Hashtable playerProperties, MatchmakingMode matchingType, TypedLobby typedLobby, string sqlLobbyFilter)
213         {
214             
if (this.DebugOut >= DebugLevel.INFO)
215             {
216                 
this.Listener.DebugReturn(DebugLevel.INFO, "OpJoinRandomRoom()");
217             }
218
219             Hashtable expectedRoomProperties =
new Hashtable();
220             expectedRoomProperties.MergeStringKeys(expectedCustomRoomProperties);
221             
if (expectedMaxPlayers > 0)
222             {
223                 expectedRoomProperties[GameProperties.MaxPlayers] = expectedMaxPlayers;
224             }
225
226             Dictionary<
byte, object> opParameters = new Dictionary<byte, object>();
227             
if (expectedRoomProperties.Count > 0)
228             {
229                 opParameters[ParameterCode.GameProperties] = expectedRoomProperties;
230             }
231
232             
if (playerProperties != null && playerProperties.Count > 0)
233             {
234                 opParameters[ParameterCode.PlayerProperties] = playerProperties;
235             }
236
237             
if (matchingType != MatchmakingMode.FillRoom)
238             {
239                 opParameters[ParameterCode.MatchMakingType] = (
byte)matchingType;
240             }
241
242             
if (typedLobby != null)
243             {
244                 opParameters[ParameterCode.LobbyName] = typedLobby.Name;
245                 opParameters[ParameterCode.LobbyType] = (
byte)typedLobby.Type;
246             }
247
248             
if (!string.IsNullOrEmpty(sqlLobbyFilter))
249             {
250                 opParameters[ParameterCode.Data] = sqlLobbyFilter;
251             }
252
253             
// UnityEngine.Debug.LogWarning("OpJoinRandom: " + opParameters.ToStringFull());
254             
return this.OpCustom(OperationCode.JoinRandomGame, opParameters, true);
255         }

256
257         ///
<summary>
258         ///
Request the rooms and online status for a list of friends (each client must set a unique username via OpAuthenticate).
259         ///
</summary>
260         ///
<remarks>
261         ///
Used on Master Server to find the rooms played by a selected list of users.
262         ///
Users identify themselves by using OpAuthenticate with a unique username.
263         ///
The list of usernames must be fetched from some other source (not provided by Photon).
264         ///
265         ///
The server response includes 2 arrays of info (each index matching a friend from the request):
266         ///
ParameterCode.FindFriendsResponseOnlineList = bool[] of online states
267         ///
ParameterCode.FindFriendsResponseRoomIdList = string[] of room names (empty string if not in a room)
268         ///
</remarks>
269         ///
<param name="friendsToFind">Array of friend's names (make sure they are unique).</param>
270         ///
<returns>If the operation could be sent (requires connection).</returns>
271         
public virtual bool OpFindFriends(string[] friendsToFind)
272         {
273             Dictionary<
byte, object> opParameters = new Dictionary<byte, object>();
274             
if (friendsToFind != null && friendsToFind.Length > 0)
275             {
276                 opParameters[ParameterCode.FindFriendsRequestList] = friendsToFind;
277             }
278
279             
return this.OpCustom(OperationCode.FindFriends, opParameters, true);
280         }
281
282         
public bool OpSetCustomPropertiesOfActor(int actorNr, Hashtable actorProperties, bool broadcast, byte channelId)
283         {
284             
return this.OpSetPropertiesOfActor(actorNr, actorProperties.StripToStringKeys(), broadcast, channelId);
285         }
286
287         
protected bool OpSetPropertiesOfActor(int actorNr, Hashtable actorProperties, bool broadcast, byte channelId)
288         {
289             
if (this.DebugOut >= DebugLevel.INFO)
290             {
291                 
this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfActor()");
292             }
293
294             
if (actorNr <= 0 || actorProperties == null)
295             {
296                 
if (this.DebugOut >= DebugLevel.INFO)
297                 {
298                     
this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfActor not sent. ActorNr must be > 0 and actorProperties != null.");
299                 }
300                 
return false;
301             }
302
303             Dictionary<
byte, object> opParameters = new Dictionary<byte, object>();
304             opParameters.Add(ParameterCode.Properties, actorProperties);
305             opParameters.Add(ParameterCode.ActorNr, actorNr);
306             
if (broadcast)
307             {
308                 opParameters.Add(ParameterCode.Broadcast, broadcast);
309             }
310
311             
return this.OpCustom((byte)OperationCode.SetProperties, opParameters, broadcast, channelId);
312         }
313
314         
protected void OpSetPropertyOfRoom(byte propCode, object value)
315         {
316             Hashtable properties =
new Hashtable();
317             properties[propCode] =
value;
318             
this.OpSetPropertiesOfRoom(properties, true, (byte)0);
319         }
320
321         
public bool OpSetCustomPropertiesOfRoom(Hashtable gameProperties, bool broadcast, byte channelId)
322         {
323             
return this.OpSetPropertiesOfRoom(gameProperties.StripToStringKeys(), broadcast, channelId);
324         }
325
326         
public bool OpSetPropertiesOfRoom(Hashtable gameProperties, bool broadcast, byte channelId)
327         {
328             
if (this.DebugOut >= DebugLevel.INFO)
329             {
330                 
this.Listener.DebugReturn(DebugLevel.INFO, "OpSetPropertiesOfRoom()");
331             }
332
333             Dictionary<
byte, object> opParameters = new Dictionary<byte, object>();
334             opParameters.Add(ParameterCode.Properties, gameProperties);
335             
if (broadcast)
336             {
337                 opParameters.Add(ParameterCode.Broadcast,
true);
338             }
339
340             
return this.OpCustom((byte)OperationCode.SetProperties, opParameters, broadcast, channelId);
341         }

342
343         ///
<summary>
344         ///
Sends this app's appId and appVersion to identify this application server side.
345         ///
This is an async request which triggers a OnOperationResponse() call.
346         ///
</summary>
347         ///
<remarks>
348         ///
This operation makes use of encryption, if that is established before.
349         ///
See: EstablishEncryption(). Check encryption with IsEncryptionAvailable.
350         ///
This operation is allowed only once per connection (multiple calls will have ErrorCode != Ok).
351         ///
</remarks>
352         ///
<param name="appId">Your application's name or ID to authenticate. This is assigned by Photon Cloud (webpage).</param>
353         ///
<param name="appVersion">The client's version (clients with differing client appVersions are separated and players don't meet).</param>
354         ///
<param name="userId"></param>
355         ///
<param name="authValues"></param>
356         ///
<param name="regionCode">When authenticating for a specific region, a NameServer will forward you to that region's MasterServer.</param>
357         ///
<returns>If the operation could be sent (has to be connected).</returns>
358         
public virtual bool OpAuthenticate(string appId, string appVersion, string userId, AuthenticationValues authValues, string regionCode)
359         {
360             
if (this.DebugOut >= DebugLevel.INFO)
361             {
362                 
this.Listener.DebugReturn(DebugLevel.INFO, "OpAuthenticate()");
363             }
364
365             Dictionary<
byte, object> opParameters = new Dictionary<byte, object>();
366             
if (authValues != null && authValues.Secret != null)
367             {
368                 opParameters[ParameterCode.Secret] = authValues.Secret;
369                 
return this.OpCustom(OperationCode.Authenticate, opParameters, true, (byte)0, false);
370             }
371
372             opParameters[ParameterCode.AppVersion] = appVersion;
373             opParameters[ParameterCode.ApplicationId] = appId;
374
375             
if (!string.IsNullOrEmpty(regionCode))
376             {
377                 opParameters[ParameterCode.Region] = regionCode;
378             }
379
380             
if (!string.IsNullOrEmpty(userId))
381             {
382                 opParameters[ParameterCode.UserId] = userId;
383             }
384
385
386             
if (authValues != null && authValues.AuthType != CustomAuthenticationType.None)
387             {
388                 
if (!this.IsEncryptionAvailable)
389                 {
390                     
this.Listener.DebugReturn(DebugLevel.ERROR, "OpAuthenticate() failed. When you want Custom Authentication encryption is mandatory.");
391                     
return false;
392                 }
393
394                 opParameters[ParameterCode.ClientAuthenticationType] = (
byte)authValues.AuthType;
395                 
if (!string.IsNullOrEmpty(authValues.Secret))
396                 {
397                     opParameters[ParameterCode.Secret] = authValues.Secret;
398                 }
399                 
//else
400                 
//{
401                     
if (!string.IsNullOrEmpty(authValues.AuthParameters))
402                     {
403                         opParameters[ParameterCode.ClientAuthenticationParams] = authValues.AuthParameters;
404                     }
405                     
if (authValues.AuthPostData != null)
406                     {
407                         opParameters[ParameterCode.ClientAuthenticationData] = authValues.AuthPostData;
408                     }
409                 
//}
410             }
411
412             
bool sent = this.OpCustom(OperationCode.Authenticate, opParameters, true, (byte)0, this.IsEncryptionAvailable);
413             
if (!sent)
414             {
415                 
this.Listener.DebugReturn(DebugLevel.ERROR, "Error calling OpAuthenticate! Did not work. Check log output, CustomAuthenticationValues and if you're connected.");
416             }
417             
return sent;
418         }

419
420
421         ///
<summary>
422         ///
Operation to handle this client's interest groups (for events in room).
423         ///
</summary>
424         ///
<remarks>
425         ///
Note the difference between passing null and byte[0]:
426         ///
null won't add/remove any groups.
427         ///
byte[0] will add/remove all (existing) groups.
428         ///
First, removing groups is executed. This way, you could leave all groups and join only the ones provided.
429         ///
</remarks>
430         ///
<param name="groupsToRemove">Groups to remove from interest. Null will not remove any. A byte[0] will remove all.</param>
431         ///
<param name="groupsToAdd">Groups to add to interest. Null will not add any. A byte[0] will add all current.</param>
432         ///
<returns></returns>
433         
public virtual bool OpChangeGroups(byte[] groupsToRemove, byte[] groupsToAdd)
434         {
435             
if (this.DebugOut >= DebugLevel.ALL)
436             {
437                 
this.Listener.DebugReturn(DebugLevel.ALL, "OpChangeGroups()");
438             }
439
440             Dictionary<
byte, object> opParameters = new Dictionary<byte, object>();
441             
if (groupsToRemove != null)
442             {
443                 opParameters[(
byte)LiteOpKey.Remove] = groupsToRemove;
444             }
445             
if (groupsToAdd != null)
446             {
447                 opParameters[(
byte)LiteOpKey.Add] = groupsToAdd;
448             }
449
450             
return this.OpCustom((byte)LiteOpCode.ChangeGroups, opParameters, true, 0);
451         }

452
453
454         ///
<summary>
455         ///
Send an event with custom code/type and any content to the other players in the same room.
456         ///
</summary>
457         ///
<remarks>This override explicitly uses another parameter order to not mix it up with the implementation for Hashtable only.</remarks>
458         ///
<param name="eventCode">Identifies this type of event (and the content). Your game's event codes can start with 0.</param>
459         ///
<param name="customEventContent">Any serializable datatype (including Hashtable like the other OpRaiseEvent overloads).</param>
460         ///
<param name="sendReliable">If this event has to arrive reliably (potentially repeated if it's lost).</param>
461         ///
<param name="raiseEventOptions">Contains (slightly) less often used options. If you pass null, the default options will be used.</param>
462         ///
<returns>If operation could be enqueued for sending. Sent when calling: Service or SendOutgoingCommands.</returns>
463         
public virtual bool OpRaiseEvent(byte eventCode, object customEventContent, bool sendReliable, RaiseEventOptions raiseEventOptions)
464         {
465             opParameters.Clear();
// re-used private variable to avoid many new Dictionary() calls (garbage collection)
466             opParameters[(
byte)LiteOpKey.Code] = (byte)eventCode;
467             
if (customEventContent != null)
468             {
469                 opParameters[(
byte) LiteOpKey.Data] = customEventContent;
470             }
471
472             
if (raiseEventOptions == null)
473             {
474                 raiseEventOptions = RaiseEventOptions.Default;
475             }
476             
else
477             {
478                 
if (raiseEventOptions.CachingOption != EventCaching.DoNotCache)
479                 {
480                     opParameters[(
byte) LiteOpKey.Cache] = (byte) raiseEventOptions.CachingOption;
481                 }
482                 
if (raiseEventOptions.Receivers != ReceiverGroup.Others)
483                 {
484                     opParameters[(
byte) LiteOpKey.ReceiverGroup] = (byte) raiseEventOptions.Receivers;
485                 }
486                 
if (raiseEventOptions.InterestGroup != 0)
487                 {
488                     opParameters[(
byte) LiteOpKey.Group] = (byte) raiseEventOptions.InterestGroup;
489                 }
490                 
if (raiseEventOptions.TargetActors != null)
491                 {
492                     opParameters[(
byte) LiteOpKey.ActorList] = raiseEventOptions.TargetActors;
493                 }
494                 
if (raiseEventOptions.ForwardToWebhook)
495                 {
496                     opParameters[(
byte) ParameterCode.EventForward] = true; //TURNBASED
497                 }
498             }
499
500             
return this.OpCustom((byte)LiteOpCode.RaiseEvent, opParameters, sendReliable, raiseEventOptions.SequenceChannel, raiseEventOptions.Encrypt);
501         }
502     }

503
504
505     ///
<summary>
506     ///
Class for constants. These (int) values represent error codes, as defined and sent by the Photon LoadBalancing logic.
507     ///
Pun uses these constants internally.
508     ///
</summary>
509     ///
<remarks>Codes from the Photon Core are negative. Default-app error codes go down from short.max.</remarks>
510     
internal class ErrorCode
511     {

512         ///
<summary>(0) is always "OK", anything else an error or specific situation.</summary>
513         
public const int Ok = 0;
514
515         
// server - Photon low(er) level: <= 0
516
517         ///
<summary>
518         ///
(-3) Operation can't be executed yet (e.g. OpJoin can't be called before being authenticated, RaiseEvent cant be used before getting into a room).
519         ///
</summary>
520         ///
<remarks>
521         ///
Before you call any operations on the Cloud servers, the automated client workflow must complete its authorization.
522         ///
In PUN, wait until State is: JoinedLobby (with AutoJoinLobby = true) or ConnectedToMaster (AutoJoinLobby = false)
523         ///
</remarks>
524         
public const int OperationNotAllowedInCurrentState = -3;
525
526         ///
<summary>(-2) The operation you called is not implemented on the server (application) you connect to. Make sure you run the fitting applications.</summary>
527         
public const int InvalidOperationCode = -2;
528
529         ///
<summary>(-1) Something went wrong in the server. Try to reproduce and contact Exit Games.</summary>
530         
public const int InternalServerError = -1;
531
532         
// server - PhotonNetwork: 0x7FFF and down
533         
// logic-level error codes start with short.max
534
535         ///
<summary>(32767) Authentication failed. Possible cause: AppId is unknown to Photon (in cloud service).</summary>
536         
public const int InvalidAuthentication = 0x7FFF;
537
538         ///
<summary>(32753) The Authentication ticket expired. Usually, this is refreshed behind the scenes. Connect (and authorize) again.</summary>
539         
public const int AuthenticationTicketExpired = 0x7FF1;
540
541         ///
<summary>(32766) GameId (name) already in use (can't create another). Change name.</summary>
542         
public const int GameIdAlreadyExists = 0x7FFF - 1;
543
544         ///
<summary>(32765) Game is full. This rarely happens when some player joined the room before your join completed.</summary>
545         
public const int GameFull = 0x7FFF - 2;
546
547         ///
<summary>(32764) Game is closed and can't be joined. Join another game.</summary>
548         
public const int GameClosed = 0x7FFF - 3;
549
550         [Obsolete(
"No longer used, cause random matchmaking is no longer a process.")] public const int AlreadyMatched =
551             
0x7FFF - 4;
552
553         ///
<summary>(32762) Not in use currently.</summary>
554         
public const int ServerFull = 0x7FFF - 5;
555
556         ///
<summary>(32761) Not in use currently.</summary>
557         
public const int UserBlocked = 0x7FFF - 6;
558
559         ///
<summary>(32760) Random matchmaking only succeeds if a room exists thats neither closed nor full. Repeat in a few seconds or create a new room.</summary>
560         
public const int NoRandomMatchFound = 0x7FFF - 7;
561
562         ///
<summary>(32758) Join can fail if the room (name) is not existing (anymore). This can happen when players leave while you join.</summary>
563         
public const int GameDoesNotExist = 0x7FFF - 9;
564
565         ///
<summary>(32757) Authorization on the Photon Cloud failed because the concurrent users (CCU) limit of the app's subscription is reached.</summary>
566         ///
<remarks>
567         ///
Unless you have a plan with "CCU Burst", clients might fail the authentication step during connect.
568         ///
Affected client are unable to call operations. Please note that players who end a game and return
569         ///
to the master server will disconnect and re-connect, which means that they just played and are rejected
570         ///
in the next minute / re-connect.
571         ///
This is a temporary measure. Once the CCU is below the limit, players will be able to connect an play again.
572         ///
573         ///
OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen.
574         ///
Self-hosted Photon servers with a CCU limited license won't let a client connect at all.
575         ///
</remarks>
576         
public const int MaxCcuReached = 0x7FFF - 10;
577
578         ///
<summary>(32756) Authorization on the Photon Cloud failed because the app's subscription does not allow to use a particular region's server.</summary>
579         ///
<remarks>
580         ///
Some subscription plans for the Photon Cloud are region-bound. Servers of other regions can't be used then.
581         ///
Check your master server address and compare it with your Photon Cloud Dashboard's info.
582         ///
https://cloud.exitgames.com/dashboard
583         ///
584         ///
OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen.
585         ///
Self-hosted Photon servers with a CCU limited license won't let a client connect at all.
586         ///
</remarks>
587         
public const int InvalidRegion = 0x7FFF - 11;
588
589         ///
<summary>
590         ///
(32755) Custom Authentication of the user failed due to setup reasons (see Cloud Dashboard) or the provided user data (like username or token). Check error message for details.
591         ///
</summary>
592         
public const int CustomAuthenticationFailed = 0x7FFF - 12;
593
594         ///
<summary>
595         ///
(32752) Also known as "PluginReportedError". A call to an external web service (WebHook) failed and in turn, caused the operation to fail. Check the debug message (increase the logging level, if needed).
596         ///
</summary>
597         
public const int WebHookCallFailed = 0x7FFF - 15;
598     }

599
600
601     ///
<summary>
602     ///
Class for constants. These (byte) values define "well known" properties for an Actor / Player.
603     ///
Pun uses these constants internally.
604     ///
</summary>
605     ///
<remarks>
606     ///
"Custom properties" have to use a string-type as key. They can be assigned at will.
607     ///
</remarks>
608     
public class ActorProperties
609     {

610         ///
<summary>(255) Name of a player/actor.</summary>
611         
public const byte PlayerName = 255; // was: 1
612
613         ///
<summary>(254) Tells you if the player is currently in this game (getting events live).</summary>
614         ///
<remarks>A server-set value for async games, where players can leave the game and return later.</remarks>
615         
public const byte IsInactive = 254;
616     }

617
618
619     ///
<summary>
620     ///
Class for constants. These (byte) values are for "well known" room/game properties used in Photon Loadbalancing.
621     ///
Pun uses these constants internally.
622     ///
</summary>
623     ///
<remarks>
624     ///
"Custom properties" have to use a string-type as key. They can be assigned at will.
625     ///
</remarks>
626     
public class GameProperties
627     {

628         ///
<summary>(255) Max number of players that "fit" into this room. 0 is for "unlimited".</summary>
629         
public const byte MaxPlayers = 255;
630         ///
<summary>(254) Makes this room listed or not in the lobby on master.</summary>
631         
public const byte IsVisible = 254;
632         ///
<summary>(253) Allows more players to join a room (or not).</summary>
633         
public const byte IsOpen = 253;
634         ///
<summary>(252) Current count of players in the room. Used only in the lobby on master.</summary>
635         
public const byte PlayerCount = 252;
636         ///
<summary>(251) True if the room is to be removed from room listing (used in update to room list in lobby on master)</summary>
637         
public const byte Removed = 251;
638         ///
<summary>(250) A list of the room properties to pass to the RoomInfo list in a lobby. This is used in CreateRoom, which defines this list once per room.</summary>
639         
public const byte PropsListedInLobby = 250;
640         ///
<summary>(249) Equivalent of Operation Join parameter CleanupCacheOnLeave.</summary>
641         
public const byte CleanupCacheOnLeave = 249;
642     }

643
644
645     ///
<summary>
646     ///
Class for constants. These values are for events defined by Photon Loadbalancing.
647     ///
Pun uses these constants internally.
648     ///
</summary>
649     ///
<remarks>They start at 255 and go DOWN. Your own in-game events can start at 0.</remarks>
650     
public class EventCode
651     {

652         ///
<summary>(230) Initial list of RoomInfos (in lobby on Master)</summary>
653         
public const byte GameList = 230;
654         ///
<summary>(229) Update of RoomInfos to be merged into "initial" list (in lobby on Master)</summary>
655         
public const byte GameListUpdate = 229;
656         ///
<summary>(228) Currently not used. State of queueing in case of server-full</summary>
657         
public const byte QueueState = 228;
658         ///
<summary>(227) Currently not used. Event for matchmaking</summary>
659         
public const byte Match = 227;
660         ///
<summary>(226) Event with stats about this application (players, rooms, etc)</summary>
661         
public const byte AppStats = 226;
662         ///
<summary>(224) This event provides a list of lobbies with their player and game counts.</summary>
663         
public const byte TypedLobbyStats = 224;
664         ///
<summary>(210) Internally used in case of hosting by Azure</summary>
665         
[Obsolete("TCP routing was removed after becoming obsolete.")]
666         
public const byte AzureNodeInfo = 210;
667         ///
<summary>(255) Event Join: someone joined the game. The new actorNumber is provided as well as the properties of that actor (if set in OpJoin).</summary>
668         
public const byte Join = (byte)LiteEventCode.Join;
669         ///
<summary>(254) Event Leave: The player who left the game can be identified by the actorNumber.</summary>
670         
public const byte Leave = (byte)LiteEventCode.Leave;
671         ///
<summary>(253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set.</summary>
672         
public const byte PropertiesChanged = (byte)LiteEventCode.PropertiesChanged;
673         ///
<summary>(253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set.</summary>
674         
[Obsolete("Use PropertiesChanged now.")]
675         
public const byte SetProperties = (byte)LiteEventCode.PropertiesChanged;
676     }

677
678
679     ///
<summary>
680     ///
Class for constants. Codes for parameters of Operations and Events.
681     ///
Pun uses these constants internally.
682     ///
</summary>
683     
public class ParameterCode
684     {

685         ///
<summary>(237) Optional parameter to suppress events Join and Leave for a room (which might be used as lobby/chat room then).</summary>
686         
public const byte SuppressRoomEvents = 237;
687         ///
<summary>(234) Optional parameter of OpRaiseEvent to forward the event to some web-service.</summary>
688         
public const byte EventForward = 234;
689
690         ///
<summary>(233) Used in EvLeave to describe if a user is inactive (and might come back) or not. In async / Turnbased games, inactive is default.</summary>
691         
public const byte IsInactive = (byte)233;
692
693         ///
<summary>(232) Used when creating rooms to define if any userid can join the room only once.</summary>
694         
public const byte CheckUserOnJoin = (byte)232;
695
696         ///
<summary>(230) Address of a (game) server to use.</summary>
697         
public const byte Address = 230;
698         ///
<summary>(229) Count of players in rooms (connected to game servers for this application, used in stats event)</summary>
699         
public const byte PeerCount = 229;
700         ///
<summary>(228) Count of games in this application (used in stats event)</summary>
701         
public const byte GameCount = 228;
702         ///
<summary>(227) Count of players on the master server (connected to master server for this application, looking for games, used in stats event)</summary>
703         
public const byte MasterPeerCount = 227;
704         ///
<summary>(225) User's ID</summary>
705         
public const byte UserId = 225;
706         ///
<summary>(224) Your application's ID: a name on your own Photon or a GUID on the Photon Cloud</summary>
707         
public const byte ApplicationId = 224;
708         ///
<summary>(223) Not used (as "Position" currently). If you get queued before connect, this is your position</summary>
709         
public const byte Position = 223;
710         ///
<summary>(223) Modifies the matchmaking algorithm used for OpJoinRandom. Allowed parameter values are defined in enum MatchmakingMode.</summary>
711         
public const byte MatchMakingType = 223;
712         ///
<summary>(222) List of RoomInfos about open / listed rooms</summary>
713         
public const byte GameList = 222;
714         ///
<summary>(221) Internally used to establish encryption</summary>
715         
public const byte Secret = 221;
716         ///
<summary>(220) Version of your application</summary>
717         
public const byte AppVersion = 220;
718
719         
// Codes for Azure / TCP Proxy are removed
720
721         ///
<summary>(255) Code for the gameId/roomName (a unique name per room). Used in OpJoin and similar.</summary>
722         
public const byte RoomName = (byte)LiteOpKey.GameId;
723         ///
<summary>(250) Code for broadcast parameter of OpSetProperties method.</summary>
724         
public const byte Broadcast = (byte)LiteOpKey.Broadcast;
725         ///
<summary>(252) Code for list of players in a room. Currently not used.</summary>
726         
public const byte ActorList = (byte)LiteOpKey.ActorList;
727         ///
<summary>(254) Code of the Actor of an operation. Used for property get and set.</summary>
728         
public const byte ActorNr = (byte)LiteOpKey.ActorNr;
729         ///
<summary>(249) Code for property set (Hashtable).</summary>
730         
public const byte PlayerProperties = (byte)LiteOpKey.ActorProperties;
731         ///
<summary>(245) Code of data/custom content of an event. Used in OpRaiseEvent.</summary>
732         
public const byte CustomEventContent = (byte)LiteOpKey.Data;
733         ///
<summary>(245) Code of data of an event. Used in OpRaiseEvent.</summary>
734         
public const byte Data = (byte)LiteOpKey.Data;
735         ///
<summary>(244) Code used when sending some code-related parameter, like OpRaiseEvent's event-code.</summary>
736         ///
<remarks>This is not the same as the Operation's code, which is no longer sent as part of the parameter Dictionary in Photon 3.</remarks>
737         
public const byte Code = (byte)LiteOpKey.Code;
738         ///
<summary>(248) Code for property set (Hashtable).</summary>
739         
public const byte GameProperties = (byte)LiteOpKey.GameProperties;
740         ///
<summary>
741         ///
(251) Code for property-set (Hashtable). This key is used when sending only one set of properties.
742         ///
If either ActorProperties or GameProperties are used (or both), check those keys.
743         ///
</summary>
744         
public const byte Properties = (byte)LiteOpKey.Properties;
745         ///
<summary>(253) Code of the target Actor of an operation. Used for property set. Is 0 for game</summary>
746         
public const byte TargetActorNr = (byte)LiteOpKey.TargetActorNr;
747         ///
<summary>(246) Code to select the receivers of events (used in Lite, Operation RaiseEvent).</summary>
748         
public const byte ReceiverGroup = (byte)LiteOpKey.ReceiverGroup;
749         ///
<summary>(247) Code for caching events while raising them.</summary>
750         
public const byte Cache = (byte)LiteOpKey.Cache;
751         ///
<summary>(241) Bool parameter of CreateGame Operation. If true, server cleans up roomcache of leaving players (their cached events get removed).</summary>
752         
public const byte CleanupCacheOnLeave = (byte)241;
753
754         ///
<summary>(240) Code for "group" operation-parameter (as used in Op RaiseEvent).</summary>
755         
public const byte Group = LiteOpKey.Group;
756         ///
<summary>(239) The "Remove" operation-parameter can be used to remove something from a list. E.g. remove groups from player's interest groups.</summary>
757         
public const byte Remove = LiteOpKey.Remove;
758         ///
<summary>(238) The "Add" operation-parameter can be used to add something to some list or set. E.g. add groups to player's interest groups.</summary>
759         
public const byte Add = LiteOpKey.Add;
760
761
762         ///
<summary>(236) Time To Live (TTL) for a room when the last player leaves. Keeps room in memory for case a player re-joins soon. In milliseconds.</summary>
763         
public const byte EmptyRoomTTL = 236;
764
765         ///
<summary>(235) Time To Live (TTL) for an 'actor' in a room. If a client disconnects, this actor is inactive first and removed after this timeout. In milliseconds.</summary>
766         
public const byte PlayerTTL = 235;
767
768
769         ///
<summary>(217) This key's (byte) value defines the target custom authentication type/service the client connects with. Used in OpAuthenticate</summary>
770         
public const byte ClientAuthenticationType = 217;
771
772         ///
<summary>(216) This key's (string) value provides parameters sent to the custom authentication type/service the client connects with. Used in OpAuthenticate</summary>
773         
public const byte ClientAuthenticationParams = 216;
774
775         ///
<summary>(215) Makes the server create a room if it doesn't exist. OpJoin uses this to always enter a room, unless it exists and is full/closed.</summary>
776         
public const byte CreateIfNotExists = 215;
777
778         ///
<summary>(215) The JoinMode enum defines which variant of joining a room will be executed: Join only if available, create if not exists or re-join.</summary>
779         ///
<remarks>Replaces CreateIfNotExists which was only a bool-value.</remarks>
780         
public const byte JoinMode = 215;
781
782         ///
<summary>(214) This key's (string or byte[]) value provides parameters sent to the custom authentication service setup in Photon Dashboard. Used in OpAuthenticate</summary>
783         
public const byte ClientAuthenticationData = 214;
784
785         ///
<summary>(213) Used in matchmaking-related methods and when creating a room to name a lobby (to join or to attach a room to).</summary>
786         
public const byte LobbyName = (byte)213;
787
788         ///
<summary>(212) Used in matchmaking-related methods and when creating a room to define the type of a lobby. Combined with the lobby name this identifies the lobby.</summary>
789         
public const byte LobbyType = (byte)212;
790
791         ///
<summary>(211) This (optional) parameter can be sent in Op Authenticate to turn on Lobby Stats (info about lobby names and their user- and game-counts). See: PhotonNetwork.Lobbies</summary>
792         
public const byte LobbyStats = (byte)211;
793
794         ///
<summary>(210) Used for region values in OpAuth and OpGetRegions.</summary>
795         
public const byte Region = (byte)210;
796
797         ///
<summary>(209) Path of the WebRPC that got called. Also known as "WebRpc Name". Type: string.</summary>
798         
public const byte UriPath = 209;
799
800         ///
<summary>(208) Parameters for a WebRPC as: Dictionary<string, object>. This will get serialized to JSon.</summary>
801         
public const byte WebRpcParameters = 208;
802
803         ///
<summary>(207) ReturnCode for the WebRPC, as sent by the web service (not by Photon, which uses ErrorCode). Type: byte.</summary>
804         
public const byte WebRpcReturnCode = 207;
805
806         ///
<summary>(206) Message returned by WebRPC server. Analog to Photon's debug message. Type: string.</summary>
807         
public const byte WebRpcReturnMessage = 206;
808
809
810         ///
<summary>(1) Used in Op FindFriends request. Value must be string[] of friends to look up.</summary>
811         
public const byte FindFriendsRequestList = (byte)1;
812
813         ///
<summary>(1) Used in Op FindFriends response. Contains bool[] list of online states (false if not online).</summary>
814         
public const byte FindFriendsResponseOnlineList = (byte)1;
815
816         ///
<summary>(2) Used in Op FindFriends response. Contains string[] of room names ("" where not known or no room joined).</summary>
817         
public const byte FindFriendsResponseRoomIdList = (byte)2;
818     }

819
820
821     ///
<summary>
822     ///
Class for constants. Contains operation codes.
823     ///
Pun uses these constants internally.
824     ///
</summary>
825     
public class OperationCode
826     {

827         ///
<summary>(230) Authenticates this peer and connects to a virtual application</summary>
828         
public const byte Authenticate = 230;
829         ///
<summary>(229) Joins lobby (on master)</summary>
830         
public const byte JoinLobby = 229;
831         ///
<summary>(228) Leaves lobby (on master)</summary>
832         
public const byte LeaveLobby = 228;
833         ///
<summary>(227) Creates a game (or fails if name exists)</summary>
834         
public const byte CreateGame = 227;
835         ///
<summary>(226) Join game (by name)</summary>
836         
public const byte JoinGame = 226;
837         ///
<summary>(225) Joins random game (on master)</summary>
838         
public const byte JoinRandomGame = 225;
839
840         
// public const byte CancelJoinRandom = 224; // obsolete, cause JoinRandom no longer is a "process". now provides result immediately
841
842         ///
<summary>(254) Code for OpLeave, to get out of a room.</summary>
843         
public const byte Leave = (byte)LiteOpCode.Leave;
844         ///
<summary>(253) Raise event (in a room, for other actors/players)</summary>
845         
public const byte RaiseEvent = (byte)LiteOpCode.RaiseEvent;
846         ///
<summary>(252) Set Properties (of room or actor/player)</summary>
847         
public const byte SetProperties = (byte)LiteOpCode.SetProperties;
848         ///
<summary>(251) Get Properties</summary>
849         
public const byte GetProperties = (byte)LiteOpCode.GetProperties;
850
851         ///
<summary>(248) Operation code to change interest groups in Rooms (Lite application and extending ones).</summary>
852         
public const byte ChangeGroups = (byte)LiteOpCode.ChangeGroups;
853
854         ///
<summary>(222) Request the rooms and online status for a list of friends (by name, which should be unique).</summary>
855         
public const byte FindFriends = 222;
856
857         ///
<summary>(221) Request statistics about a specific list of lobbies (their user and game count).</summary>
858         
public const byte GetLobbyStats = 221;
859
860         ///
<summary>(220) Get list of regional servers from a NameServer.</summary>
861         
public const byte GetRegions = 220;
862
863         ///
<summary>(219) WebRpc Operation.</summary>
864         
public const byte WebRpc = 219;
865     }
866 }

867
868
869 ///
<summary>
870 ///
Options for matchmaking rules for OpJoinRandom.
871 ///
</summary>
872 public
enum MatchmakingMode : byte
873 {

874     ///
<summary>Fills up rooms (oldest first) to get players together as fast as possible. Default.</summary>
875     ///
<remarks>Makes most sense with MaxPlayers > 0 and games that can only start with more players.</remarks>
876     FillRoom =
0,
877     ///
<summary>Distributes players across available rooms sequentially but takes filter into account. Without filter, rooms get players evenly distributed.</summary>
878     SerialMatching =
1,
879     ///
<summary>Joins a (fully) random room. Expected properties must match but aside from this, any available room might be selected.</summary>
880     RandomMatching =
2
881 }

882
883 ///
<summary>
884 ///
Options for optional "Custom Authentication" services used with Photon. Used by OpAuthenticate after connecting to Photon.
885 ///
</summary>
886 public
enum CustomAuthenticationType : byte
887 {

888     ///
<summary>Use a custom authentification service. Currently the only implemented option.</summary>
889     Custom =
0,
890
891     ///
<summary>Authenticates users by their Steam Account. Set auth values accordingly!</summary>
892     Steam =
1,
893
894     ///
<summary>Authenticates users by their Facebook Account. Set auth values accordingly!</summary>
895     Facebook =
2,
896
897     ///
<summary>Disables custom authentification. Same as not providing any AuthenticationValues for connect (more precisely for: OpAuthenticate).</summary>
898     None =
byte.MaxValue
899 }

900
901 ///
<summary>
902 ///
Container for "Custom Authentication" values in Photon (default: user and token). Set AuthParameters before connecting - all else is handled.
903 ///
</summary>
904 ///
<remarks>
905 ///
Custom Authentication lets you verify end-users by some kind of login or token. It sends those
906 ///
values to Photon which will verify them before granting access or disconnecting the client.
907 ///
908 ///
The Photon Cloud Dashboard will let you enable this feature and set important server values for it.
909 ///
https://cloud.exitgames.com/dashboard
910 ///
</remarks>
911 public
class AuthenticationValues
912 {

913     ///
<summary>The type of custom authentication provider that should be used. Currently only "Custom" or "None" (turns this off).</summary>
914     
public CustomAuthenticationType AuthType = CustomAuthenticationType.Custom;
915
916     ///
<summary>This string must contain any (http get) parameters expected by the used authentication service. By default, username and token.</summary>
917     ///
<remarks>Standard http get parameters are used here and passed on to the service that's defined in the server (Photon Cloud Dashboard).</remarks>
918     
public string AuthParameters; // { get { return a; } set { a = value; UnityEngine.Debug.LogWarning("AuthParameters set: " + value + " server: " + PhotonNetwork.ServerAddress); } }
919     
//private string a;
920
921     ///
<summary>After initial authentication, Photon provides a secret for this client / user, which is subsequently used as (cached) validation.</summary>
922     
public string Secret; // { get { return s; } set { s = value; UnityEngine.Debug.LogWarning("Secret set: " + value + " server: " + PhotonNetwork.ServerAddress); } }
923     
//private string s;
924
925     ///
<summary>Data to be passed-on to the auth service via POST. Default: null (not sent). Either string or byte[] (see setters).</summary>
926     
public object AuthPostData { get; private set; }
927
928     ///
<summary>Sets the data to be passed-on to the auth service via POST.</summary>
929     ///
<param name="byteData">Binary token / auth-data to pass on. Empty string will set AuthPostData to null.</param>
930     
public virtual void SetAuthPostData(string stringData)
931     {
932         
this.AuthPostData = (string.IsNullOrEmpty(stringData)) ? null : stringData;
933     }

934
935     ///
<summary>Sets the data to be passed-on to the auth service via POST.</summary>
936     ///
<param name="byteData">Binary token / auth-data to pass on.</param>
937     
public virtual void SetAuthPostData(byte[] byteData)
938     {
939         
this.AuthPostData = byteData;
940     }

941
942     ///
<summary>Creates the default parameter string from a user and token value, escaping both. Alternatively set AuthParameters yourself.</summary>
943     ///
<remarks>The default parameter string is: "username={user}&token={token}"</remarks>
944     ///
<param name="user">Name or other end-user ID used in custom authentication service.</param>
945     ///
<param name="token">Token provided by authentication service to be used on initial "login" to Photon.</param>
946     
public virtual void SetAuthParameters(string user, string token)
947     {
948         
this.AuthParameters = "username=" + System.Uri.EscapeDataString(user) + "&token=" + System.Uri.EscapeDataString(token);
949     }
950
951     
public override string ToString()
952     {
953         
return AuthParameters + " s: " + Secret;
954     }
955 }


----------------------------------------------------------------------------

Loadbalancing Framework for Photon - Copyright (C) 2011 Exit Games GmbH

Provides the operations needed to use the loadbalancing server app(s).

developer@exitgames.com

----------------------------------------------------------------------------

Internally used by PUN, a LoadbalancingPeer provides the operations and enum

definitions needed to use the Photon Loadbalancing server (or the Photon Cloud).

The LoadBalancingPeer does not keep a state, instead this is done by a LoadBalancingClient.

private readonly Dictionary opParameters = new Dictionary(); used in OpRaiseEvent() (avoids lots of new Dictionary() calls)

Joins the lobby on the Master Server, where you get a list of RoomInfos of currently open rooms.

This is an async request which triggers a OnOperationResponse() call.

If the operation could be sent (has to be connected).

Leaves the lobby on the Master Server.

This is an async request which triggers a OnOperationResponse() call.

If the operation could be sent (has to be connected).

Don't use this method directly, unless you know how to cache and apply customActorProperties.

The PhotonNetwork methods will handle player and room properties for you and call this method.

op[ParameterCode.Broadcast] = true; TODO: check if this also makes sense when creating a room?! broadcast actor properties

gameProperties[GameProperties.IsOpen] = roomOptions.isOpen; TODO: check default value. dont send this then

gameProperties[GameProperties.IsVisible] = roomOptions.isVisible; TODO: check default value. dont send this then

op[ParameterCode.CleanupCacheOnLeave] = true; this is actually setting the room's config

gameProperties[GameProperties.CleanupCacheOnLeave] = true; this is only informational for the clients which join

UnityEngine.Debug.Log("CreateGame: " + SupportClass.DictionaryToString(op));

LoadBalancingPeer.OpJoinRoom

op[ParameterCode.Broadcast] = true; broadcast actor properties

op[ParameterCode.CleanupCacheOnLeave] = true; this is actually setting the room's config

gameProperties[GameProperties.CleanupCacheOnLeave] = true; this is only informational for the clients which join

UnityEngine.Debug.Log("JoinGame: " + SupportClass.DictionaryToString(op));

Operation to join a random, available room. Overloads take additional player properties.

This is an async request which triggers a OnOperationResponse() call.

If all rooms are closed or full, the OperationResponse will have a returnCode of ErrorCode.NoRandomMatchFound.

If successful, the OperationResponse contains a gameserver address and the name of some room.

Optional. A room will only be joined, if it matches these custom properties (with string keys).

Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.

This player's properties (custom and well known).

Selects one of the available matchmaking algorithms. See MatchmakingMode enum for options.

If the operation could be sent currently (requires connection).

UnityEngine.Debug.LogWarning("OpJoinRandom: " + opParameters.ToStringFull());

Request the rooms and online status for a list of friends (each client must set a unique username via OpAuthenticate).

Used on Master Server to find the rooms played by a selected list of users.

Users identify themselves by using OpAuthenticate with a unique username.

The list of usernames must be fetched from some other source (not provided by Photon).

The server response includes 2 arrays of info (each index matching a friend from the request):

ParameterCode.FindFriendsResponseOnlineList = bool[] of online states

ParameterCode.FindFriendsResponseRoomIdList = string[] of room names (empty string if not in a room)

Array of friend's names (make sure they are unique).

If the operation could be sent (requires connection).

Sends this app's appId and appVersion to identify this application server side.

This is an async request which triggers a OnOperationResponse() call.

This operation makes use of encryption, if that is established before.

See: EstablishEncryption(). Check encryption with IsEncryptionAvailable.

This operation is allowed only once per connection (multiple calls will have ErrorCode != Ok).

Your application's name or ID to authenticate. This is assigned by Photon Cloud (webpage).

The client's version (clients with differing client appVersions are separated and players don't meet).

When authenticating for a specific region, a NameServer will forward you to that region's MasterServer.

If the operation could be sent (has to be connected).

else

{

}

Operation to handle this client's interest groups (for events in room).

Note the difference between passing null and byte[0]:

null won't addremove any groups.

byte[0] will addremove all (existing) groups.

First, removing groups is executed. This way, you could leave all groups and join only the ones provided.

Groups to remove from interest. Null will not remove any. A byte[0] will remove all.

Groups to add to interest. Null will not add any. A byte[0] will add all current.

Send an event with custom codetype and any content to the other players in the same room.

This override explicitly uses another parameter order to not mix it up with the implementation for Hashtable only.

Identifies this type of event (and the content). Your game's event codes can start with 0.

Any serializable datatype (including Hashtable like the other OpRaiseEvent overloads).

If this event has to arrive reliably (potentially repeated if it's lost).

Contains (slightly) less often used options. If you pass null, the default options will be used.

If operation could be enqueued for sending. Sent when calling: Service or SendOutgoingCommands.

opParameters.Clear(); re-used private variable to avoid many new Dictionary() calls (garbage collection)

opParameters[(byte) ParameterCode.EventForward] = true; TURNBASED

Class for constants. These (int) values represent error codes, as defined and sent by the Photon LoadBalancing logic.

Pun uses these constants internally.

Codes from the Photon Core are negative. Default-app error codes go down from short.max.

(0) is always "OK", anything else an error or specific situation.

server - Photon low(er) level: <= 0

(-3) Operation can't be executed yet (e.g. OpJoin can't be called before being authenticated, RaiseEvent cant be used before getting into a room).

Before you call any operations on the Cloud servers, the automated client workflow must complete its authorization.

In PUN, wait until State is: JoinedLobby (with AutoJoinLobby = true) or ConnectedToMaster (AutoJoinLobby = false)

(-2) The operation you called is not implemented on the server (application) you connect to. Make sure you run the fitting applications.

(-1) Something went wrong in the server. Try to reproduce and contact Exit Games.

server - PhotonNetwork: 0x7FFF and down

logic-level error codes start with short.max

(32767) Authentication failed. Possible cause: AppId is unknown to Photon (in cloud service).

(32753) The Authentication ticket expired. Usually, this is refreshed behind the scenes. Connect (and authorize) again.

(32766) GameId (name) already in use (can't create another). Change name.

(32765) Game is full. This rarely happens when some player joined the room before your join completed.

(32764) Game is closed and can't be joined. Join another game.

(32762) Not in use currently.

(32761) Not in use currently.

(32760) Random matchmaking only succeeds if a room exists thats neither closed nor full. Repeat in a few seconds or create a new room.

(32758) Join can fail if the room (name) is not existing (anymore). This can happen when players leave while you join.

(32757) Authorization on the Photon Cloud failed because the concurrent users (CCU) limit of the app's subscription is reached.

Unless you have a plan with "CCU Burst", clients might fail the authentication step during connect.

Affected client are unable to call operations. Please note that players who end a game and return

to the master server will disconnect and re-connect, which means that they just played and are rejected

in the next minute re-connect.

This is a temporary measure. Once the CCU is below the limit, players will be able to connect an play again.

OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen.

Self-hosted Photon servers with a CCU limited license won't let a client connect at all.

(32756) Authorization on the Photon Cloud failed because the app's subscription does not allow to use a particular region's server.

Some subscription plans for the Photon Cloud are region-bound. Servers of other regions can't be used then.

Check your master server address and compare it with your Photon Cloud Dashboard's info.

https:cloud.exitgames.comdashboard

OpAuthorize is part of connection workflow but only on the Photon Cloud, this error can happen.

Self-hosted Photon servers with a CCU limited license won't let a client connect at all.

(32755) Custom Authentication of the user failed due to setup reasons (see Cloud Dashboard) or the provided user data (like username or token). Check error message for details.

(32752) Also known as "PluginReportedError". A call to an external web service (WebHook) failed and in turn, caused the operation to fail. Check the debug message (increase the logging level, if needed).

Class for constants. These (byte) values define "well known" properties for an Actor Player.

Pun uses these constants internally.

"Custom properties" have to use a string-type as key. They can be assigned at will.

(255) Name of a playeractor.

public const byte PlayerName = 255; was: 1

(254) Tells you if the player is currently in this game (getting events live).

A server-set value for async games, where players can leave the game and return later.

Class for constants. These (byte) values are for "well known" roomgame properties used in Photon Loadbalancing.

Pun uses these constants internally.

"Custom properties" have to use a string-type as key. They can be assigned at will.

(255) Max number of players that "fit" into this room. 0 is for "unlimited".

(254) Makes this room listed or not in the lobby on master.

(253) Allows more players to join a room (or not).

(252) Current count of players in the room. Used only in the lobby on master.

(251) True if the room is to be removed from room listing (used in update to room list in lobby on master)

(250) A list of the room properties to pass to the RoomInfo list in a lobby. This is used in CreateRoom, which defines this list once per room.

(249) Equivalent of Operation Join parameter CleanupCacheOnLeave.

Class for constants. These values are for events defined by Photon Loadbalancing.

Pun uses these constants internally.

They start at 255 and go DOWN. Your own in-game events can start at 0.

(230) Initial list of RoomInfos (in lobby on Master)

(229) Update of RoomInfos to be merged into "initial" list (in lobby on Master)

(228) Currently not used. State of queueing in case of server-full

(227) Currently not used. Event for matchmaking

(226) Event with stats about this application (players, rooms, etc)

(224) This event provides a list of lobbies with their player and game counts.

(210) Internally used in case of hosting by Azure

(255) Event Join: someone joined the game. The new actorNumber is provided as well as the properties of that actor (if set in OpJoin).

(254) Event Leave: The player who left the game can be identified by the actorNumber.

(253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set.

(253) When you call OpSetProperties with the broadcast option "on", this event is fired. It contains the properties being set.

Class for constants. Codes for parameters of Operations and Events.

Pun uses these constants internally.

(237) Optional parameter to suppress events Join and Leave for a room (which might be used as lobbychat room then).

(234) Optional parameter of OpRaiseEvent to forward the event to some web-service.

(233) Used in EvLeave to describe if a user is inactive (and might come back) or not. In async Turnbased games, inactive is default.

(232) Used when creating rooms to define if any userid can join the room only once.

(230) Address of a (game) server to use.

(229) Count of players in rooms (connected to game servers for this application, used in stats event)

(228) Count of games in this application (used in stats event)

(227) Count of players on the master server (connected to master server for this application, looking for games, used in stats event)

(225) User's ID

(224) Your application's ID: a name on your own Photon or a GUID on the Photon Cloud

(223) Not used (as "Position" currently). If you get queued before connect, this is your position

(223) Modifies the matchmaking algorithm used for OpJoinRandom. Allowed parameter values are defined in enum MatchmakingMode.

(222) List of RoomInfos about open listed rooms

(221) Internally used to establish encryption

(220) Version of your application

Codes for Azure TCP Proxy are removed

(255) Code for the gameIdroomName (a unique name per room). Used in OpJoin and similar.

(250) Code for broadcast parameter of OpSetProperties method.

(252) Code for list of players in a room. Currently not used.

(254) Code of the Actor of an operation. Used for property get and set.

(249) Code for property set (Hashtable).

(245) Code of datacustom content of an event. Used in OpRaiseEvent.

(245) Code of data of an event. Used in OpRaiseEvent.

(244) Code used when sending some code-related parameter, like OpRaiseEvent's event-code.

This is not the same as the Operation's code, which is no longer sent as part of the parameter Dictionary in Photon 3.

(248) Code for property set (Hashtable).

(251) Code for property-set (Hashtable). This key is used when sending only one set of properties.

If either ActorProperties or GameProperties are used (or both), check those keys.

(253) Code of the target Actor of an operation. Used for property set. Is 0 for game

(246) Code to select the receivers of events (used in Lite, Operation RaiseEvent).

(247) Code for caching events while raising them.

(241) Bool parameter of CreateGame Operation. If true, server cleans up roomcache of leaving players (their cached events get removed).

(240) Code for "group" operation-parameter (as used in Op RaiseEvent).

(239) The "Remove" operation-parameter can be used to remove something from a list. E.g. remove groups from player's interest groups.

(238) The "Add" operation-parameter can be used to add something to some list or set. E.g. add groups to player's interest groups.

(236) Time To Live (TTL) for a room when the last player leaves. Keeps room in memory for case a player re-joins soon. In milliseconds.

(235) Time To Live (TTL) for an 'actor' in a room. If a client disconnects, this actor is inactive first and removed after this timeout. In milliseconds.

(217) This key's (byte) value defines the target custom authentication typeservice the client connects with. Used in OpAuthenticate

(216) This key's (string) value provides parameters sent to the custom authentication typeservice the client connects with. Used in OpAuthenticate

(215) Makes the server create a room if it doesn't exist. OpJoin uses this to always enter a room, unless it exists and is fullclosed.

(215) The JoinMode enum defines which variant of joining a room will be executed: Join only if available, create if not exists or re-join.

Replaces CreateIfNotExists which was only a bool-value.

(214) This key's (string or byte[]) value provides parameters sent to the custom authentication service setup in Photon Dashboard. Used in OpAuthenticate

(213) Used in matchmaking-related methods and when creating a room to name a lobby (to join or to attach a room to).

(212) Used in matchmaking-related methods and when creating a room to define the type of a lobby. Combined with the lobby name this identifies the lobby.

(211) This (optional) parameter can be sent in Op Authenticate to turn on Lobby Stats (info about lobby names and their user- and game-counts). See: PhotonNetwork.Lobbies

(210) Used for region values in OpAuth and OpGetRegions.

(209) Path of the WebRPC that got called. Also known as "WebRpc Name". Type: string.

(208) Parameters for a WebRPC as: Dictionary. This will get serialized to JSon.

(207) ReturnCode for the WebRPC, as sent by the web service (not by Photon, which uses ErrorCode). Type: byte.

(206) Message returned by WebRPC server. Analog to Photon's debug message. Type: string.

(1) Used in Op FindFriends request. Value must be string[] of friends to look up.

(1) Used in Op FindFriends response. Contains bool[] list of online states (false if not online).

(2) Used in Op FindFriends response. Contains string[] of room names ("" where not known or no room joined).

Class for constants. Contains operation codes.

Pun uses these constants internally.

(230) Authenticates this peer and connects to a virtual application

(229) Joins lobby (on master)

(228) Leaves lobby (on master)

(227) Creates a game (or fails if name exists)

(226) Join game (by name)

(225) Joins random game (on master)

public const byte CancelJoinRandom = 224; obsolete, cause JoinRandom no longer is a "process". now provides result immediately

(254) Code for OpLeave, to get out of a room.

(253) Raise event (in a room, for other actorsplayers)

(252) Set Properties (of room or actorplayer)

(251) Get Properties

(248) Operation code to change interest groups in Rooms (Lite application and extending ones).

(222) Request the rooms and online status for a list of friends (by name, which should be unique).

(221) Request statistics about a specific list of lobbies (their user and game count).

(220) Get list of regional servers from a NameServer.

(219) WebRpc Operation.

Options for matchmaking rules for OpJoinRandom.

Fills up rooms (oldest first) to get players together as fast as possible. Default.

Makes most sense with MaxPlayers > 0 and games that can only start with more players.

Distributes players across available rooms sequentially but takes filter into account. Without filter, rooms get players evenly distributed.

Joins a (fully) random room. Expected properties must match but aside from this, any available room might be selected.

Options for optional "Custom Authentication" services used with Photon. Used by OpAuthenticate after connecting to Photon.

Use a custom authentification service. Currently the only implemented option.

Authenticates users by their Steam Account. Set auth values accordingly!

Authenticates users by their Facebook Account. Set auth values accordingly!

Disables custom authentification. Same as not providing any AuthenticationValues for connect (more precisely for: OpAuthenticate).

Container for "Custom Authentication" values in Photon (default: user and token). Set AuthParameters before connecting - all else is handled.

Custom Authentication lets you verify end-users by some kind of login or token. It sends those

values to Photon which will verify them before granting access or disconnecting the client.

The Photon Cloud Dashboard will let you enable this feature and set important server values for it.

https:cloud.exitgames.comdashboard

The type of custom authentication provider that should be used. Currently only "Custom" or "None" (turns this off).

This string must contain any (http get) parameters expected by the used authentication service. By default, username and token.

Standard http get parameters are used here and passed on to the service that's defined in the server (Photon Cloud Dashboard).

public string AuthParameters; { get { return a; } set { a = value; UnityEngine.Debug.LogWarning("AuthParameters set: " + value + " server: " + PhotonNetwork.ServerAddress); } }

private string a;

After initial authentication, Photon provides a secret for this client user, which is subsequently used as (cached) validation.

public string Secret; { get { return s; } set { s = value; UnityEngine.Debug.LogWarning("Secret set: " + value + " server: " + PhotonNetwork.ServerAddress); } }

private string s;

Data to be passed-on to the auth service via POST. Default: null (not sent). Either string or byte[] (see setters).

Sets the data to be passed-on to the auth service via POST.

Binary token auth-data to pass on. Empty string will set AuthPostData to null.

Sets the data to be passed-on to the auth service via POST.

Binary token auth-data to pass on.

Creates the default parameter string from a user and token value, escaping both. Alternatively set AuthParameters yourself.

The default parameter string is: "username={user}&token={token}"

Name or other end-user ID used in custom authentication service.

Token provided by authentication service to be used on initial "login" to Photon.




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.434 lượt xem

Gõ tìm kiếm nhanh...